/**
 *                     Remixvym (version 0.8.4)
 *             Copyright (c) 2010 by RemixLab, DISI-UNAL
 *            http://www.disi.unal.edu.co/grupos/remixlab/
 *
 * This Java package provides classes to visualize Mind Maps created in VYM
 * (View Your Mind) in a Processing Sketch
 *
 * @author Alvaro Lopez, Juan Baquero
 *
 * This source file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * A copy of the GNU General Public License is available on the World Wide Web
 * at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by
 * writing to the Free Software Foundation, 51 Franklin Street, Fifth Floor
 * Boston, MA 02110, USA
 */
package remixlab.remixvym;

import processing.core.*;
import processing.xml.XMLElement;
import remixlab.remixvym.core.mindmap.Node;
import remixlab.remixvym.xml.XMLReader;

/**
 * PXMLReader loads the XML file from VYM and save the information into a {@link Node} object.
 * <p>Implements XMLReader. 
 */

public class PXMLReader implements XMLReader{

	private static final long serialVersionUID = 1L;
	// Root node
	private Node father;
	
	//PApplet containing the map
	private PApplet parent;
	
	/**
	 * Start the PApplet
	 * @eventos del mouse en processingparam win The {@link PApplet} containing the mind map. 
	 */
	public PXMLReader(PApplet win)
	{
		parent=win;
	}
	
	/**
	 * Set the new {@link Node} object and load the XML file. 
	 * @param url The path for the XML file.
	 */
	public void setupFile(String url) {
		
		father = new Node();
		analyze(url);
	}
	
	/**
	 * Set the new {@link Node} object and load the XML file. 
	 * @param xml The path for the XML file.
	 */
	public void setupXML2(String xml) {
		father = new Node();
		//analyzeStream(xml);
		this.ReadXML(xml);
	}

	/**
	 * Check the XML file.
	 * @param xml The path for the XML file.
	 */
	private void analyze(String url) {
		// Get the XML's root.
		XMLElement xml = new XMLElement(parent, url);
		//System.out.println("cadena="+xml.toString());
		// Beginning in the first child of the root, try to recursively cover
		// the tree. (The root contains info about the program, so it is omitted)
		XMLElement index = xml.getChild(0);
		recursive(index, father,null);

		// Results
		getInfo(father);
	}
	
	/**
	 * Check the XML file as a stream.
	 * @param xml The stream representation of the XML file.
	 */
	/*private void analyzeStream(String xmlStream) {
		// Get the XML's root.
		
		XMLElement xml = new XMLElement(xmlStream);
		// Beginning in the first child of the root, try to recursively cover
		// the tree. (The root contains info about the program, so it is omitted)
		XMLElement index = xml.getChild(0);
		recursive(index, father,null);
		getInfo(father);
	}*/

	private void getInfo(Node h) {
		//Post-order traversal of the tree
		for (int i = 0; i < h.children.size(); i++) {
			getInfo(h.children.get(i));
		}
	}
	
	/**
	 * To build the map, it processes each node finding properties like hidden nodes,
	 * position, size, and so on.
	 * */
	private void recursive(XMLElement xml, Node node, Node nodefather) {
		
		//boolean hide;
		
		//if(nodefather==null) hide=false;
		//else hide = nodefather.hide;
		
		//if(xml.getAttribute("x1")!=null && !hide)
		if(xml.getFloat("x1",-1)!=-1 || xml.getFloat("x1",2)!=2)
		{
			//node.x1 = (int)Float.parseFloat(xml.getAttribute("x1"));
			node.x1 = (int)(xml.getFloat("x1"));
			//node.y1 = (int)Float.parseFloat(xml.getAttribute("y1"));
			node.y1 = (int)(xml.getFloat("y1"));
			//node.x2 = (int)Float.parseFloat(xml.getAttribute("x2"));
			node.x2 = (int)(xml.getFloat("x2"));
			//node.y2 = (int)Float.parseFloat(xml.getAttribute("y2"));
			node.y2 = (int)(xml.getFloat("y2"));
			node.calculate();
			node.hide = false;
		}else
		{
			node.hide = true;
		}
		/*
		if(xml.getAttribute("scrolled")!=null && xml.getAttribute("scrolled").equals("yes")){
			node.scrolled=true;		
			node.scrolledNow=true;	
		}*/
		if(!xml.getString("scrolled","descabellado").equals("descabellado") && xml.getString("scrolled").equals("yes")){
			node.scrolled=true;		
			node.scrolledNow=true;	
		}
		
		node.setFather(nodefather);
		if(node.getFather()!=null)
			node.setLevel(node.getFather().level+1);
		else
			node.setLevel(1);
		
		int size = xml.getChildCount();

		//Checks each children and distinguishes between branches, flags, headings and float Images.
		for (int i = 0; i < size; i++) 
		{
			if (xml.getChild(i).getName().compareTo("branch") == 0) 
			{
				Node newNode = new Node();
				node.children.add(newNode);
				recursive(xml.getChild(i), newNode,node);
			}
			else if (xml.getChild(i).getName().compareTo("floatimage") == 0) 
			{
				//node.contImage = xml.getChild(i).getAttribute("orgName");
				node.contImage = xml.getChild(i).getString("orgName");
			}
			else if(xml.getChild(i).getName().compareTo("standardflag")== 0)
			{
				node.emoticones.add(xml.getChild(i).getContent());						
			}
			else if(xml.getChild(i).getName().compareTo("heading")== 0)
			{
				node.setInfo(" "+xml.getChild(i).getContent());
			}
			
		}

		//Hides the node if it has level>=4 and has children
		if(node.getLevel()>=4 && node.children.size()>0){
			node.scrolled=true;
			node.scrolledNow=true;
			for(int i=0; i<node.children.size();i++){
				node.children.get(i).hide=true;
			}
		}
		
		if(node.children.size()>0){
			//changeChildrenXPositions(node);
		    //changeChildrenYPositions(node);
		}
		//The string contains info about associated videos, sketches and links. 
		String fakeAddress=node.getInfo().toString();
		
		//0: VIDEO  1:LINK  2: SKETCH  3:NODESTYLE  4:LINKSTYLE 
		int[] tagIndexes = new int[5];
		String[] tags = new String[5];
		
		tags[0]="VIDEO";
		tags[1]="LINK";
		tags[2]="SKETCH";
		tags[3]="NODESTYLE";
		tags[4]="LINKSTYLE";
		//Search each tag into node's content
		for(int i = 0; i<tags.length; i++){
			tagIndexes[i] = fakeAddress.indexOf(tags[i]+"=");
		}
		//Then, proceed to sort them increasingly, so, the string is parsed from left to right.
		for(int i = 0; i < tagIndexes.length-1; i++){
			for(int j = i+1; j < tagIndexes.length; j++){
				if(tagIndexes[i]>tagIndexes[j]){
					int temp = tagIndexes[i];
					tagIndexes[i] = tagIndexes[j];
					tagIndexes[j] = temp;
				}
			}
		}
		
		boolean hasName = false;
		for(int i = 0; i < tagIndexes.length; i++){
			//Ignore if tag is not found
			if(tagIndexes[i]==-1)	continue;
			if(!hasName){
				//The node has not a name, provide a default one.
				if(tagIndexes[i]==0)	{node.setInfo("Node"); hasName=true;}
				else node.setInfo(fakeAddress.substring(0, tagIndexes[i]-1));
			}
			
			//If tag index is different than -1, then it exists. Also, avoid taking into account the space among tags
			String data = ((i==tagIndexes.length-1)? fakeAddress.substring(tagIndexes[i]):fakeAddress.substring(tagIndexes[i], tagIndexes[i+1]-1));
			//data contains the tag and its value, so check what kind of tag is and process it.
			
			//TODO: Do it dynamically
			//Video
			if(data.startsWith("VIDEO=")){
				data = data.substring("VIDEO=".length());
				node.contVideo = data;
			}
			//Link (Image)
			else if(data.startsWith("LINK=")){
				data = data.substring("LINK=".length());
				node.contLink = data;
			}
			//Sketch
			else if(data.startsWith("SKETCH=")){
				data = data.substring("SKETCH=".length());

				//Search info about sketch's size
				int pos3a = data.lastIndexOf("w");
				int pos3b = data.lastIndexOf("x");
				int pos3c = data.lastIndexOf("h");
				try{
					if(pos3a>0 && pos3a<pos3b && pos3b<pos3c){
						node.prefsketchWidth = Integer.parseInt(data.substring(pos3a+1, pos3b));
						node.prefsketchHeight = Integer.parseInt(data.substring(pos3c+1));
					}else
						throw new Exception();
				}catch(Exception e){
					node.prefsketchHeight=200;
					node.prefsketchWidth=200;
				}
				node.contSketch = (pos3a>0? data.substring(0,pos3a): data);
			}
			//Node Style
			else if(data.startsWith("NODESTYLE=")){
				data = data.substring("NODESTYLE=".length());
				node.nodeStyle = data;
			}
			//Link Style
			else if(data.startsWith("LINKSTYLE=")){
				data = data.substring("LINKSTYLE=".length());
				//Currently, linkStyle should not be set on a node info. 
			}
		}
	}
	
	/**
	 *Returns the root {@link Node} object.
	 */
	public Node getRoot() {
		return father;
	}
	
	/*
	 * alternativa de creacion del XMLElement
	 */
	public void ReadXML(String nameFile) {
		// Get the XML's root.
		//System.out.println("cadena antes de "+xmlStream);
		//xmlStream = xmlStream.substring(xmlStream.length()-3,
			//	xmlStream.length());
		
		XMLElement xml = new XMLElement(nameFile);
		// Beginning in the first child of the root, try to recursively cover
		// the tree. (The root contains info about the program, so it is omitted)
		XMLElement index = xml.getChild(0);
		recursive(index, father,null);
		getInfo(father);
	}

}